----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    10:39:18 09/18/2013 
-- Design Name: 
-- Module Name:    alu - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity alu is
Port (	Clk		: in	STD_LOGIC;
			Control	: in	STD_LOGIC_VECTOR (5 downto 0);
			Operand1	: in	STD_LOGIC_VECTOR (31 downto 0);
			Operand2	: in	STD_LOGIC_VECTOR (31 downto 0);
			Result1	: out	STD_LOGIC_VECTOR (31 downto 0);
			Result2	: out	STD_LOGIC_VECTOR (31 downto 0);
			Debug		: out	STD_LOGIC_VECTOR (31 downto 0));
end alu;

architecture Behavioral of alu is
	constant NOP_INSTR 	: std_logic_vector 	:= "00" & X"0"; 
	constant ADD_INSTR 	: std_logic_vector 	:= "00" & X"1"; 
	constant ADDU_INSTR 	: std_logic_vector 	:= "00" & X"2"; 
	constant SUB_INSTR 	: std_logic_vector 	:= "00" & X"3"; 
	constant SUBU_INSTR 	: std_logic_vector 	:= "00" & X"4"; 
	constant MULT_INSTR 	: std_logic_vector 	:= "00" & X"5"; 
	constant MULTU_INSTR : std_logic_vector 	:= "00" & X"6"; 
	constant DIV_INSTR 	: std_logic_vector 	:= "00" & X"7"; 
	constant DIVU_INSTR 	: std_logic_vector 	:= "00" & X"8"; 
	constant XOR_INSTR 	: std_logic_vector 	:= "00" & X"9"; 
	constant AND_INSTR 	: std_logic_vector 	:= "00" & X"A"; 
	constant OR_INSTR 	: std_logic_vector 	:= "00" & X"B"; 
	constant NOR_INSTR 	: std_logic_vector 	:= "00" & X"C"; 
	constant SRA_INSTR 	: std_logic_vector 	:= "00" & X"D"; 
	constant SRL_INSTR 	: std_logic_vector 	:= "00" & X"E"; 
	constant SLL_INSTR 	: std_logic_vector 	:= "00" & X"F"; 
	constant SLT_INSTR 	: std_logic_vector 	:= "01" & X"0"; 
	constant BEQ_INSTR 	: std_logic_vector 	:= "01" &X"1"; 
	constant BNE_INSTR 	: std_logic_vector 	:= "01" &X"2"; 

	constant BEQ_BIT 			: integer := 0;	-- is set to '1' if instruction: (BEQ A, B) and (A = B) else '0'
	constant BNE_BIT 			: integer := 1;	-- is set to '1' if instruction: (BNE A, B) and (A != B) else '0'
	constant SLT_BIT 			: integer := 2; 	-- is set to '1' if instruction: (SLT A, B) and (A < B) else '0'	
	constant OVERFLOW_BIT 	: integer := 3;
	
	component mult_div is
		port(	signControl, divControl, clock : in STD_LOGIC;
				a, b : in STD_LOGIC_VECTOR(31 downto 0);
				result : out STD_LOGIC_VECTOR(63 downto 0));
	end component;
	
	component add_sub_32 is
		 Port ( a : in  STD_LOGIC_VECTOR (31 downto 0);
				  b : in  STD_LOGIC_VECTOR (31 downto 0);
				  subControl : in STD_LOGIC;
				  sum : out  STD_LOGIC_VECTOR (31 downto 0);
				  carryOut : out  STD_LOGIC;
				  isEqual : out STD_LOGIC);
	end component;
	
	component xor_and_or_32 is
		 Port ( a : in  STD_LOGIC_VECTOR (31 downto 0);
				  b : in  STD_LOGIC_VECTOR (31 downto 0);
				  xorOutput : out  STD_LOGIC_VECTOR (31 downto 0);
				  andOutput : out  STD_LOGIC_VECTOR (31 downto 0);
				  orOutput : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	component right_shifter is
		 Port (	input : in  STD_LOGIC_VECTOR (31 downto 0);
					arthControl : in STD_LOGIC;
					shiftValue : in STD_LOGIC_VECTOR (4 downto 0);
					output : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	component left_shifter is
		 Port (	input : in  STD_LOGIC_VECTOR (31 downto 0);
					shiftValue : in STD_LOGIC_VECTOR (4 downto 0);
					output : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	signal signControl1 : STD_LOGIC := '0';
	signal divControl1 : STD_LOGIC := '0';
	signal subControl1 : STD_LOGIC := '0';
	signal carryOut31 : STD_LOGIC;
	signal isEqual1 : STD_LOGIC;
	signal addSubOutput1 : STD_LOGIC_VECTOR(31 downto 0);
	signal multDivOutput1 : STD_LOGIC_VECTOR(63 downto 0);
	
	signal xorOutput1 : STD_LOGIC_VECTOR(31 downto 0);
	signal andOutput1 : STD_LOGIC_VECTOR(31 downto 0);
	signal orOutput1 : STD_LOGIC_VECTOR(31 downto 0);
	
	signal arthControl1 : STD_LOGIC := '0';
	signal rightShifterOutput1 : STD_LOGIC_VECTOR(31 downto 0);
	signal leftShifterOutput1 : STD_LOGIC_VECTOR(31 downto 0);
	
	signal r1, r2, d : STD_LOGIC_VECTOR (31 downto 0) := X"00000000";
	
begin
		addSub1 : add_sub_32 port map(Operand1, Operand2, subControl1, addSubOutput1, carryOut31, isEqual1);
		multDiv1 : mult_div port map(signControl1, divControl1, Clk, Operand1, Operand2, multDivOutput1);
		xorAndOr1 : xor_and_or_32 port map(Operand1, Operand2, xorOutput1, andOutput1, orOutput1);
		
		rightShifter1 : right_shifter port map(Operand1, arthControl1, Operand2(4 downto 0), rightShifterOutput1);
		leftShifter1 : left_shifter port map(Operand1, Operand2(4 downto 0), leftShifterOutput1);
		
process (Clk)
begin  
   if (Clk'event and Clk = '1') then
		-- reset instruction
      if Control(5) = '1' then
         r1 <= X"00000000";
			r2 <= X"00000000";
			d <= X"00000000";
			
		-- all other instructions
      else
			if Control = NOP_INSTR then
				-- do nothing
				
			elsif Control = ADD_INSTR then
				subControl1 <= '0';
				r1 <= addSubOutput1;
				d(OVERFLOW_BIT) <= carryOut31;
				
			elsif Control = ADDU_INSTR then
				subControl1 <= '0';
				r1 <= addSubOutput1;
				
			elsif Control = SUB_INSTR then
				subControl1 <= '1';
				r1 <= addSubOutput1;
				d(OVERFLOW_BIT) <= carryOut31;
				
			elsif Control = SUBU_INSTR then
				subControl1 <= '1';
				r1 <= addSubOutput1;
			
			elsif Control = MULT_INSTR then
				signControl1 <= '1';
				divControl1 <= '0';
				r2 <= multDivOutput1(63 downto 32);
				r1 <= multDivOutput1(31 downto 0);
				
			elsif Control = MULTU_INSTR then
				signControl1 <= '0';
				divControl1 <= '0';
				r2 <= multDivOutput1(63 downto 32);
				r1 <= multDivOutput1(31 downto 0);
				
			elsif Control = DIV_INSTR then
				signControl1 <= '1';
				divControl1 <= '1';
				r2 <= multDivOutput1(63 downto 32);
				r1 <= multDivOutput1(31 downto 0);
			
			elsif Control = DIVU_INSTR then
				signControl1 <= '1';
				divControl1 <= '1';
				r2 <= multDivOutput1(63 downto 32);
				r1 <= multDivOutput1(31 downto 0);
				
			elsif Control = XOR_INSTR then
				r1 <= xorOutput1;
				
			elsif Control = AND_INSTR then
				r1 <= andOutput1;
				
			elsif Control = OR_INSTR then
				r1 <= orOutput1;
				
			elsif Control = NOR_INSTR then
				r1 <= NOT(orOutput1);
				
			elsif Control = SRA_INSTR then
				arthControl1 <= '1';
				r1 <= rightShifterOutput1;
				
			elsif Control = SRL_INSTR then
				arthControl1 <= '0';
				r1 <= rightShifterOutput1;
				
			elsif Control = SLL_INSTR then
				r1 <= leftShifterOutput1;
				
			elsif Control = SLT_INSTR then
				subControl1 <= '1';
				d(SLT_BIT) <= addSubOutput1(31);
			
			elsif Control = BEQ_INSTR then
				subControl1 <= '1';
				d(BEQ_BIT) <= isEqual1;
				
			elsif Control = BNE_INSTR then
				subControl1 <= '1';
				d(BNE_BIT) <= NOT(isEqual1);
			else
				-- do nothing
			end if;
      end if;
   end if;
end process;

	Result1 <= r1;
	Result2 <= r2;
	Debug <= d;

end Behavioral;

